package com.hymjweb.demo.framework.util.util;

import com.hymjweb.demo.framework.util.DateUtil;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;



/**
 * 验证18/15位中国公民身份证号码，并分析有效的数据
 */
public class CheckIdCard {

    private static final String verify18PatternStr = "(\\d{6})" + "(\\d{8})" + "(\\d{3})" + "([\\d[xX]]{1})";

    private static final Pattern verify18Pattern = Pattern.compile(verify18PatternStr);

    private static final String verify15PatternStr = "(\\d{6})" + "(\\d{6})" + "(\\d{3})";

    private static final Pattern verify15Pattern = Pattern.compile(verify15PatternStr);

    /**
     * 从第18到第1位的权
     */
    private static final int verify18Rights[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1 };

    /**
     * 检验码校对表
     */
    private static final String verify18CheckDigit[] = { "1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2" };

    /**
     * 地区码
     */
    private String areaNum;

    /**
     * 出生时间
     */
    private String birthdayNum;

    /**
     * 顺序号
     */
    private String seqNum;

    /**
     * 校验码
     */
    private String check_digit;

    private int length;
    
    /**
     * 校验一个身份证号码是否合法，并返回CheckIdCard对象，如果不合法则抛出异常。
     * @param IDCardNO
     * @return 
     * @author admin
     * @serialData 2018年5月30日
     */
    public static CheckIdCard check(String IDCardNO) throws Exception {
        CheckIdCard ck = new CheckIdCard(IDCardNO);
        return ck;
    }
    
    /**
     * 校验身份证是否合法
     * @param IDCardNO
     * @return 
     * @author admin
     * @serialData 2018年8月7日
     */
    public static boolean isValidated(String IDCardNO) {
        try {
            CheckIdCard ck = new CheckIdCard(IDCardNO);    
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    public boolean isMan() {
        int num = Integer.parseInt(seqNum);
        if (num % 2 == 1) {
            return true;
        } else
            return false;
    }

    /**
     * 得到生日的日期，格式：yyyy-mm-dd
     * 
     * @returnString
     */
    public String getBirthday() throws Exception {
        String FullBirthdayNum = null;
        if (length == 15)// 在生日号码前加“19”
            FullBirthdayNum = "19" + birthdayNum;
        else
            FullBirthdayNum = birthdayNum;

        String year = FullBirthdayNum.substring(0, 4);
        String month = FullBirthdayNum.substring(4, 6);
        String date = FullBirthdayNum.substring(6, 8);
        if ("00".equals(month) || "00".equals(date))
            throw new Exception("身份证号码:非有效日期");
        String sdate = year + "-" + month + "-" + date;
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            sf.parse(sdate);
        } catch (ParseException e) {
            throw new Exception("身份证号码:" + e);
        }
        return sdate;
    }

    public CheckIdCard() {

    }

    public CheckIdCard(String IDCardNO) throws Exception {
        if (IDCardNO == null)
            throw new Exception("身份证号码为空");
        length = IDCardNO.length();
        switch (length) {
            case 15:
                Verifier15(IDCardNO);
                break;
            case 18:
                Verifier18(IDCardNO);
                break;
            default:
                throw new Exception("身份证号长度不是15位或者18位");
        }
        getBirthday();
    }

    private void Verifier15(String IDCardNO) throws Exception {

        Matcher m = verify15Pattern.matcher(IDCardNO);
        if (m.matches() == false) {
            throw new Exception("身份证号码:15位号码不匹配");
        }
        areaNum = m.group(1);
        birthdayNum = m.group(2);
        seqNum = m.group(3);
    }

    private void Verifier18(String IDCardNO) throws Exception {

        Matcher m = verify18Pattern.matcher(IDCardNO);
        if (m.matches() == false) {
            throw new Exception("身份证号码:18位号码不匹配");
        }

        String year = IDCardNO.substring(6, 10);// 年份  
        String month = IDCardNO.substring(10, 12);// 月份  
        String day = IDCardNO.substring(12, 14);// 日
        if (!DateUtil.isDataFormat(year + "-" + month + "-" + day)) {
            throw new Exception("身份证生日无效");
        }

        areaNum = m.group(1);
        birthdayNum = m.group(2);
        seqNum = m.group(3);
        check_digit = m.group(4);

        // 预期的校验位:
        String expect_check_digit = getCheck_digit18(IDCardNO);

        // 如果校验位无效
        if (expect_check_digit.equalsIgnoreCase(check_digit) == false)
            //throw new fzzl.wai.sys.WarningException("身份证号码:最后一位校验码" + check_digit + "无效，期望:" + expect_check_digit);
            throw new Exception("身份证号码有错误:校验码无效，请仔细核对确保录入正确！我们以您录入的身份证号去参加保险，请确认您录入的与本人实际一致，以免得不到理赔！");
    }

    /**
     * 设置地区编码  
     * @return
     * @author 张凯
     * @serialDate 2018年3月23日
     */
    private static HashMap<String, String> getAreaCode() {
        HashMap<String, String> hashMap = new HashMap<>();
        hashMap.put("11", "北京");
        hashMap.put("12", "天津");
        hashMap.put("13", "河北");
        hashMap.put("14", "山西");
        hashMap.put("15", "内蒙古");
        hashMap.put("21", "辽宁");
        hashMap.put("22", "吉林");
        hashMap.put("23", "黑龙江");
        hashMap.put("31", "上海");
        hashMap.put("32", "江苏");
        hashMap.put("33", "浙江");
        hashMap.put("34", "安徽");
        hashMap.put("35", "福建");
        hashMap.put("36", "江西");
        hashMap.put("37", "山东");
        hashMap.put("41", "河南");
        hashMap.put("42", "湖北");
        hashMap.put("43", "湖南");
        hashMap.put("44", "广东");
        hashMap.put("45", "广西");
        hashMap.put("46", "海南");
        hashMap.put("50", "重庆");
        hashMap.put("51", "四川");
        hashMap.put("52", "贵州");
        hashMap.put("53", "云南");
        hashMap.put("54", "西藏");
        hashMap.put("61", "陕西");
        hashMap.put("62", "甘肃");
        hashMap.put("63", "青海");
        hashMap.put("64", "宁夏");
        hashMap.put("65", "新疆");
        hashMap.put("71", "台湾");
        hashMap.put("81", "香港");
        hashMap.put("82", "澳门");
        hashMap.put("91", "国外");
        return hashMap;
    }

    /**
     * 从18位/17位身份证号算出校验位
     * 
     * @paramIDCardNOString
     * @returnString
     */
    public static String getCheck_digit18(String IDCardNO) {
        // 权总值
        int sum = 0;
        for (int i = 0; i <= 16; i++) {
            int num = Integer.parseInt(IDCardNO.substring(i, i + 1));
            int right = verify18Rights[i];
            sum = sum + num * right;
        }
        // 对权总值取模
        int y = sum % 11;
        return verify18CheckDigit[y];
    }

    public static String IDCardNO15To18(String IDCardNO15) throws Exception {

        Matcher m = verify15Pattern.matcher(IDCardNO15);
        if (m.matches() == false) {
            throw new Exception("身份证号码:转换失败");
        }

        String NO17 = IDCardNO15.substring(0, 6) + "19" + IDCardNO15.substring(6, 15);
        return NO17 + getCheck_digit18(NO17);
    }

    public String getAreaNum() {
        return areaNum;
    }

    public String getBirthdayNum() {
        return birthdayNum;
    }

    /**
     * 返回校验位，只有18位身份证可用，15位时返回null
     * 
     * @returnString
     */
    public String getCheck_digitNum18() {
        return check_digit;
    }

    public int getLength() {
        return length;
    }

    public String getSeqNum() {
        return seqNum;
    }

    public String getSex() {
        if (isMan())
            return "男";
        else
            return "女";
    }

    public static void main(String[] args) {
        try {
            CheckIdCard vc = new CheckIdCard("110222198902174840");
            System.out.println(vc.getBirthday());
            System.out.println(vc.getBirthdayNum());
            System.out.println(vc.getSex());
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println("格式是否合法：" + DateUtil.isDataFormat("2018-03-01"));
    }

}
